from ctypes import *
import skf_api as skf_def  # 导入封装定义的模块，这里起了别名skf_def方便使用

# 加载动态库
skfapi_dll = cdll.LoadLibrary("mtoken_gm3000.dll")
# 设置函数原型
skf_def.set_function_prototypes(skfapi_dll)

sm4_file_name = b"sm4_file"
sm4_file_len = 16
sm4_key = bytes.fromhex('1234567890abcdef1234567890abcdef')

def skf_init_sm4_file(sm4_file_data):
    ulRslt = skf_def.ULONG(skf_def.SAR_OK)
    hdev = skf_def.HANDLE(None)
    happ = skf_def.HANDLE(None)
    hcont = skf_def.HANDLE(None)
    hkey = skf_def.HANDLE(None)
    szDevName = create_string_buffer(256)
    szAppName = create_string_buffer(256)
    szContName = create_string_buffer(256)
    pUserPin = b"123456"
    ulDevNameLen = skf_def.ULONG(256)
    ulAppNameLen = skf_def.ULONG(256)
    ulContNameLen = skf_def.ULONG(256)
    ulRetryCount = skf_def.ULONG(0)
    pappname = szAppName
    pdevname = szDevName
    pcontname = szContName

    # 调用SKF_EnumDev函数
    ulRslt.value = skfapi_dll.SKF_EnumDev(skf_def.BOOL(True), szDevName, byref(ulDevNameLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_ConnectDev函数
    ulRslt.value = skfapi_dll.SKF_ConnectDev(pdevname, byref(hdev))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_EnumApplication函数
    ulRslt.value = skfapi_dll.SKF_EnumApplication(hdev, szAppName, byref(ulAppNameLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_OpenApplication函数
    ulRslt.value = skfapi_dll.SKF_OpenApplication(hdev, pappname, byref(happ))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_VerifyPIN函数
    ulRslt.value = skfapi_dll.SKF_VerifyPIN(happ, skf_def.ULONG(skf_def.USER_TYPE), pUserPin, byref(ulRetryCount))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_EnumContainer函数
    ulRslt.value = skfapi_dll.SKF_EnumContainer(happ, szContName, byref(ulContNameLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return
    # 调用SKF_OpenContainer函数
    ulRslt.value = skfapi_dll.SKF_OpenContainer(happ, pcontname, byref(hcont))
    if ulRslt.value!= skf_def.SAR_OK:
        return


    # 删除原有sm4文件
    ulRslt.value = skfapi_dll.SKF_DeleteFile(happ, sm4_file_name)
    if ulRslt.value == skf_def.SAR_OK:
        print("文件删除成功")
    else:
        print(f"文件删除失败，错误码: {ulRslt.value}")


    # 创建新的sm4文件
    file_name_create = sm4_file_name
    # WARNING: 长度疑似没有作用。哪怕是1都能写入并读取很多数据。猜测是权限255太大了。但没有验证。
    file_size_create = 1024
    read_rights_create = 255
    write_rights_create = 255
    ulRslt.value = skfapi_dll.SKF_CreateFile(happ, file_name_create, file_size_create, read_rights_create,write_rights_create)
    if ulRslt.value == skf_def.SAR_OK:
        print("文件创建成功")
    else:
        print(f"文件创建失败，错误码: {ulRslt.value}")


    # 写入sm4密钥数据
    offset_write = 0
    # 创建一个c_ubyte类型的数组，长度与pubid字节串长度一致
    data = sm4_file_data
    data_len = len(data)
    data_array = (c_ubyte * data_len)(*data)
    ulRslt.value = skfapi_dll.SKF_WriteFile(happ, file_name_create, offset_write, data_array, len(data_array))
    if ulRslt.value == skf_def.SAR_OK:
        print("文件写入成功")
    else:
        print(f"文件写入失败，错误码: {ulRslt.value}")

    offset_read = 0
    size_read = sm4_file_len
    buffer = (skf_def.ctypes.c_ubyte * size_read)()  # 创建一个ctypes.c_ubyte类型的数组，用于存储读取的字节数据
    buffer_pointer = cast(buffer, POINTER(skf_def.ctypes.c_ubyte))
    actual_size_read = skf_def.ULONG(size_read)  # 创建一个ULONG类型变量，用于接收实际读取长度
    ulRslt.value = skfapi_dll.SKF_ReadFile(happ, file_name_create, offset_read, size_read, buffer_pointer, byref(actual_size_read))
    if ulRslt.value == skf_def.SAR_OK:
        print("文件读取成功，内容（十六进制表示）:", [hex(byte) for byte in buffer[:actual_size_read.value]])  # 以十六进制形式打印读取到的字节数据，根据实际读取长度截取
    else:
        print(f"文件读取失败，错误码: {ulRslt.value}")


    # 关闭相关句柄和释放资源，对应原来C代码中的清理部分
    if hkey:
        skfapi_dll.SKF_CloseHandle(hkey)
    if hcont:
        skfapi_dll.SKF_CloseContainer(hcont)
    if happ:
        skfapi_dll.SKF_CloseApplication(happ)
    if hdev:
        skfapi_dll.SKF_DisConnectDev(hdev)


def skf_read_sm4_file():
    ulRslt = skf_def.ULONG(skf_def.SAR_OK)
    hdev = skf_def.HANDLE(None)
    happ = skf_def.HANDLE(None)
    hcont = skf_def.HANDLE(None)
    hkey = skf_def.HANDLE(None)
    szDevName = create_string_buffer(256)
    szAppName = create_string_buffer(256)
    szContName = create_string_buffer(256)
    pUserPin = b"123456"
    ulDevNameLen = skf_def.ULONG(256)
    ulAppNameLen = skf_def.ULONG(256)
    ulContNameLen = skf_def.ULONG(256)
    ulRetryCount = skf_def.ULONG(0)
    pappname = szAppName
    pdevname = szDevName
    pcontname = szContName

    # 调用SKF_EnumDev函数
    ulRslt.value = skfapi_dll.SKF_EnumDev(skf_def.BOOL(True), szDevName, byref(ulDevNameLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return None
    # 调用SKF_ConnectDev函数
    ulRslt.value = skfapi_dll.SKF_ConnectDev(pdevname, byref(hdev))
    if ulRslt.value!= skf_def.SAR_OK:
        return None
    # 调用SKF_EnumApplication函数
    ulRslt.value = skfapi_dll.SKF_EnumApplication(hdev, szAppName, byref(ulAppNameLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return None
    # 调用SKF_OpenApplication函数
    ulRslt.value = skfapi_dll.SKF_OpenApplication(hdev, pappname, byref(happ))
    if ulRslt.value!= skf_def.SAR_OK:
        return None
    # 调用SKF_VerifyPIN函数
    ulRslt.value = skfapi_dll.SKF_VerifyPIN(happ, skf_def.ULONG(skf_def.USER_TYPE), pUserPin, byref(ulRetryCount))
    if ulRslt.value!= skf_def.SAR_OK:
        return None
    # 调用SKF_EnumContainer函数
    ulRslt.value = skfapi_dll.SKF_EnumContainer(happ, szContName, byref(ulContNameLen))
    if ulRslt.value!= skf_def.SAR_OK:
        return None
    # 调用SKF_OpenContainer函数
    ulRslt.value = skfapi_dll.SKF_OpenContainer(happ, pcontname, byref(hcont))
    if ulRslt.value!= skf_def.SAR_OK:
        return None


    offset_read = 0
    size_read = sm4_file_len
    buffer = (skf_def.ctypes.c_ubyte * size_read)()
    buffer_pointer = cast(buffer, POINTER(skf_def.ctypes.c_ubyte))
    actual_size_read = skf_def.ULONG(size_read)
    ulRslt.value = skfapi_dll.SKF_ReadFile(happ, sm4_file_name, offset_read, size_read, buffer_pointer, byref(actual_size_read))
    if ulRslt.value != skf_def.SAR_OK:
        print(f"文件读取失败，错误码: {ulRslt.value}")
        return None
    sm4_key_bytes = bytes(buffer)

    # 关闭相关句柄和释放资源，对应原来C代码中的清理部分
    if hkey:
        skfapi_dll.SKF_CloseHandle(hkey)
    if hcont:
        skfapi_dll.SKF_CloseContainer(hcont)
    if happ:
        skfapi_dll.SKF_CloseApplication(happ)
    if hdev:
        skfapi_dll.SKF_DisConnectDev(hdev)

    return sm4_key_bytes

if __name__ == "__main__":
    # skf_init_sm4_file(sm4_key)
    sm4_key_bytes = skf_read_sm4_file()
    # print("sm4_key_bytes: ",sm4_key_bytes)
    pass
